package com.yt.server.comm;

import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.yt.server.Context;
import com.yt.server.api.IServiceCapableConnection;
import com.yt.server.api.IConnection;
import com.yt.server.api.action.IActionCall;
import com.yt.server.api.action.IActionCallback;
import com.yt.server.api.event.IEvent;
import com.yt.server.api.listeners.IConnectionListener;
import com.yt.server.messaging.Packet;

/**
 * @author 刘晶
 * @Server连接,调用业务的桥梁
 */
public class Connection extends BaseConnection implements
		IServiceCapableConnection {

	protected static Logger log = LoggerFactory.getLogger(Connection.class);

	private long created = 0;

	private String clientId = null;

	private static ExecutorService notifier = null;

	private AtomicInteger lastPingTime = new AtomicInteger(-1);

	/**
	 * 当前所有用户状态
	 */
	private volatile IoSession ioSession = null;

	/**
	 * clientId生成器
	 */
	private final UUID randomGUID = new UUID();

	protected volatile int state = State.UNINIT.ordinal();

	/**
	 * 监听(连接/断开)
	 */
	private class ConnectionListener implements IConnectionListener {

		@Override
		public void notifyConnected(IConnection conn) {
			// 做连接处理
		}

		@Override
		public void notifyDisconnected(IConnection conn) {
			// 做断开处理
		}
	}

	@Override
	public IConnectionListener getConnectionListener() {
		return new ConnectionListener();
	}

	{
		log.debug("Connection created");
		created = System.currentTimeMillis();
	}

	public Connection() {
		super();
	}

	public Connection(IoSession session) {
		super(null);
		setIoSession(session);
		state = State.INIT.ordinal();
		notifier = Executors.newFixedThreadPool(2);
	}

	@Override
	public void setSate(int state) {
		this.state = state;
	}

	@Override
	public int getState() {
		return state;
	}

	@Override
	public long getCreated() {
		return created;
	}

	@Override
	public UUID getGUID() {
		return randomGUID;
	}

	@Override
	public long getReadBytes() {
		return ioSession.getReadBytes();
	}

	@Override
	public long getWrittenBytes() {
		return ioSession.getWrittenBytes();
	}

	@Override
	public boolean ping(String ping) {
		lastPingTime.set((int) (System.currentTimeMillis() & 0xffffffff));
		if (PingUtil.isReachable(ping))
			return true;
		else
			return PingUtil.pingServer(ping, 1000);
	}

	@Override
	public int getLastPingTime() {
		return lastPingTime.get();
	}

	@Override
	public void dispatchEvent(IEvent event) {
	}

	@Override
	public boolean handleEvent(IEvent event) {
		return false;
	}

	@Override
	public void notifyEvent(IEvent event) {
	}

	@Override
	public IoSession getIoSession() {
		return ioSession;
	}

	public String getClientId() {
		return clientId;
	}

	@Override
	public long getSessionId() {
		return ioSession.getId();
	}

	@Override
	public boolean isConnected() {
		return ioSession.isConnected();
	}

	@Override
	public void setIoSession(IoSession ioSession) {
		state = State.CONNECTING.ordinal();
		SocketAddress remote = ioSession.getRemoteAddress();
		if (remote instanceof InetSocketAddress) {
			remoteAddress = ((InetSocketAddress) remote).getAddress()
					.getHostAddress();
			remotePort = ((InetSocketAddress) remote).getPort();
		} else {
			remoteAddress = remote.toString();
			remotePort = -1;
		}
		remoteAddresses = new ArrayList<String>(1);
		remoteAddresses.add(remoteAddress);
		remoteAddresses = Collections.unmodifiableList(remoteAddresses);
		randomGUID.setS_id(remoteAddress);
		randomGUID.getRandomGUID(false);
		clientId = randomGUID.toString();
		this.ioSession = ioSession;
		state = State.CONNECTED.ordinal();
	}

	@Override
	public void handleRemotingPacket(final Packet packet) throws Exception {
		Runnable notification = new Runnable() {
			public void run() {
				try {
					Context.setConnectionLocal(Connection.this);
					handleRemotingPacket(packet, null);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		};
		notifier.execute(notification);
	}

	@Override
	public void handleRemotingPacket(final Packet packet,
			final IActionCallback callback) throws Exception {
		invoke(proxy.handlePacket(packet, callback));
	}

	@Override
	public void invoke(IActionCall call) throws Exception {
		actionInvoker.invoke(call);
		if (call.getException() != null) {
			log.error(call.getException().getMessage());
			throw call.getException();
		} else if (call.isSuccess() && call.getResult() != null) {
			notify(call);
		}
	}

	@Override
	public void invoke(Object params) throws Exception {
	}

	@Override
	public void notify(IActionCall call) throws Exception {
		write(proxy.handleActionCall(call));
	}

	@Override
	public void notify(Object params) throws Exception {
		Packet packet = proxy.createPacket(params);
		write(packet);
	}

	/**
	 * 写入到Flex客户端
	 */
	@Override
	public void write(Packet packet) {
		if (null != packet)
			ioSession.write(packet);
	}

	/**
	 * 写入到Mina客户端
	 */
	@Override
	public void write(IoBuffer buffer) {
		if (null != buffer)
			ioSession.write(buffer);
	}

	@Override
	public void destroy() {
		state = State.DESTROY.ordinal();
		getScope().leave(clientId);
	}
}